package net.sourceforge.peers.sip.core.useragent;

import java.io.File;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import net.sourceforge.peers.Config;
import net.sourceforge.peers.FileLogger;
import net.sourceforge.peers.Logger;
import net.sourceforge.peers.XmlConfig;
import net.sourceforge.peers.media.AbstractSoundManager;
import net.sourceforge.peers.media.Echo;
import net.sourceforge.peers.media.MediaManager;
import net.sourceforge.peers.media.MediaMode;
import net.sourceforge.peers.sdp.SDPManager;
import net.sourceforge.peers.sip.Utils;
import net.sourceforge.peers.sip.core.useragent.handlers.ByeHandler;
import net.sourceforge.peers.sip.core.useragent.handlers.CancelHandler;
import net.sourceforge.peers.sip.core.useragent.handlers.InviteHandler;
import net.sourceforge.peers.sip.core.useragent.handlers.OptionsHandler;
import net.sourceforge.peers.sip.core.useragent.handlers.RegisterHandler;
import net.sourceforge.peers.sip.syntaxencoding.SipURI;
import net.sourceforge.peers.sip.syntaxencoding.SipUriSyntaxException;
import net.sourceforge.peers.sip.transaction.TransactionManager;
import net.sourceforge.peers.sip.transactionuser.Dialog;
import net.sourceforge.peers.sip.transactionuser.DialogManager;
import net.sourceforge.peers.sip.transport.SipRequest;
import net.sourceforge.peers.sip.transport.TransportManager;


public class UserAgent {

    public final static String CONFIG_FILE = "conf" + File.separator + "peers.xml";
    public final static int RTP_DEFAULT_PORT = 8000;

    private final String peersHome;
    private final Config config;

    private final List<String> peers;
    //private List<Dialog> dialogs;

    //TODO factorize echo and captureRtpSender
    private Echo echo;

    //用户代理客户端
    private final UAC uac;
    //用户代理服务端
    private final UAS uas;

    private final DialogManager dialogManager;
    private final TransportManager transportManager;

    private int cseqCounter;
    private final SipListener sipListener;

    private final AbstractSoundManager soundManager;
    private final MediaManager mediaManager;

    public UserAgent(SipListener sipListener, String peersHome,
                     Logger logger, AbstractSoundManager soundManager)
            throws SocketException {
        this(sipListener, null, peersHome, logger, soundManager);
    }

    public UserAgent(SipListener sipListener, Config config,
                     Logger logger, AbstractSoundManager soundManager)
            throws SocketException {
        this(sipListener, config, null, logger, soundManager);
    }

    private UserAgent(SipListener sipListener, Config config, String peersHome,
                      Logger logger, AbstractSoundManager soundManager)
            throws SocketException {

        this.sipListener = sipListener;
        if (peersHome == null) {
            peersHome = Utils.DEFAULT_PEERS_HOME;
        }
        this.peersHome = peersHome;
        if (logger == null) {
            logger = new FileLogger(this.peersHome);
        }
        Logger logger1 = logger;
        if (config == null) {
            config = new XmlConfig(this.peersHome + File.separator
                    + CONFIG_FILE, logger1);
        }
        this.config = config;

        cseqCounter = 1;

        String buf = "starting user agent [" +
                "myAddress: " +
                config.getLocalInetAddress().getHostAddress() + ", " +
                "sipPort: " +
                config.getSipPort() + ", " +
                "userpart: " +
                config.getUserPart() + ", " +
                "domain: " +
                config.getDomain() + "]";
        logger.info(buf);

        //transaction user

        dialogManager = new DialogManager(logger);

        //transaction

        TransactionManager transactionManager = new TransactionManager(logger);

        //transport

        transportManager = new TransportManager(transactionManager, config, logger);

        transactionManager.setTransportManager(transportManager);

        //core

        InviteHandler inviteHandler = new InviteHandler(this,
                dialogManager,
                transactionManager,
                transportManager,
                logger);
        CancelHandler cancelHandler = new CancelHandler(this,
                dialogManager,
                transactionManager,
                transportManager,
                logger);
        ByeHandler byeHandler = new ByeHandler(this,
                dialogManager,
                transactionManager,
                transportManager,
                logger);
        OptionsHandler optionsHandler = new OptionsHandler(this,
                transactionManager,
                transportManager,
                logger);
        RegisterHandler registerHandler = new RegisterHandler(this,
                transactionManager,
                transportManager,
                logger);

        InitialRequestManager initialRequestManager =
                new InitialRequestManager(
                        this,
                        inviteHandler,
                        cancelHandler,
                        byeHandler,
                        optionsHandler,
                        registerHandler,
                        dialogManager,
                        transactionManager,
                        transportManager,
                        logger);
        MidDialogRequestManager midDialogRequestManager =
                new MidDialogRequestManager(
                        this,
                        inviteHandler,
                        cancelHandler,
                        byeHandler,
                        optionsHandler,
                        registerHandler,
                        dialogManager,
                        transactionManager,
                        transportManager,
                        logger);

        uas = new UAS(this,
                initialRequestManager,
                midDialogRequestManager,
                dialogManager,
                transactionManager,
                transportManager);

        uac = new UAC(this,
                initialRequestManager,
                midDialogRequestManager,
                dialogManager,
                transactionManager,
                transportManager,
                logger);

        ChallengeManager challengeManager = new ChallengeManager(config,
                initialRequestManager,
                midDialogRequestManager,
                dialogManager,
                logger);
        registerHandler.setChallengeManager(challengeManager);
        inviteHandler.setChallengeManager(challengeManager);
        byeHandler.setChallengeManager(challengeManager);

        peers = new ArrayList<>();

        SDPManager sdpManager = new SDPManager(this, logger);
        inviteHandler.setSdpManager(sdpManager);
        optionsHandler.setSdpManager(sdpManager);

        this.soundManager = soundManager;
        mediaManager = new MediaManager(this, logger);
    }

    // client methods

    public void close() {
        transportManager.closeTransports();
        config.setPublicInetAddress(null);
    }

    public SipRequest register() throws SipUriSyntaxException {
        return uac.register();
    }

    public void unregister() throws SipUriSyntaxException {
        uac.unregister();
    }

    public SipRequest invite(String requestUri, String callId)
            throws SipUriSyntaxException {
        return uac.invite(requestUri, callId);
    }

    public void terminate(SipRequest sipRequest) {
        uac.terminate(sipRequest);
    }

    public void acceptCall(SipRequest sipRequest, Dialog dialog) {
        uas.acceptCall(sipRequest, dialog);
    }

    public void rejectCall(SipRequest sipRequest) {
        uas.rejectCall(sipRequest);
    }


    public List<String> getPeers() {
        return peers;
    }


    public String generateCSeq(String method) {

        return String.valueOf(cseqCounter++) +
                ' ' +
                method;
    }

    public boolean isRegistered() {
        return uac.getInitialRequestManager().getRegisterHandler()
                .isRegistered();
    }

    public UAS getUas() {
        return uas;
    }

    public UAC getUac() {
        return uac;
    }

    public DialogManager getDialogManager() {
        return dialogManager;
    }

    public int getSipPort() {
        return transportManager.getSipPort();
    }

    public int getRtpPort() {
        return config.getRtpPort();
    }

    public String getDomain() {
        return config.getDomain();
    }

    public String getUserpart() {
        return config.getUserPart();
    }

    public MediaMode getMediaMode() {
        return config.getMediaMode();
    }

    public boolean isMediaDebug() {
        return config.isMediaDebug();
    }

    public SipURI getOutboundProxy() {
        return config.getOutboundProxy();
    }

    public Echo getEcho() {
        return echo;
    }

    public void setEcho(Echo echo) {
        this.echo = echo;
    }

    public SipListener getSipListener() {
        return sipListener;
    }

    public AbstractSoundManager getSoundManager() {
        return soundManager;
    }

    public MediaManager getMediaManager() {
        return mediaManager;
    }

    public Config getConfig() {
        return config;
    }

    public String getPeersHome() {
        return peersHome;
    }

    public TransportManager getTransportManager() {
        return transportManager;
    }
}
